"""Service layer for new chat session & messages (independent)."""

from __future__ import annotations

from sqlalchemy.orm import Session
from sqlalchemy import func
from typing import Optional
from datetime import datetime

from app.models.chat_session import ChatSession
from app.models.chat_message import ChatMessage


class ChatSessionService:
    def create_session(
        self,
        db: Session,
        user_id: int,
        title: str | None,
        system_prompt: str | None,
        model_name: str | None,
        book_id: int | None,
        meta: dict | None = None,
    ) -> ChatSession:
        # 自增默认标题：统计该用户已有会话数 +1
        if not title:
            existing_count = (
                db.query(func.count(ChatSession.id))
                .filter(ChatSession.user_id == user_id)
                .scalar()
                or 0
            )
            title = f"会话{existing_count + 1}"
        session = ChatSession(
            user_id=user_id,
            title=title,
            system_prompt=system_prompt,
            model_name=model_name,
            book_id=book_id,
            meta=meta,
        )
        db.add(session)
        db.commit()
        db.refresh(session)
        return session

    def list_sessions(
        self, db: Session, user_id: int, limit: int = 30, offset: int = 0
    ):
        query = (
            db.query(ChatSession)
            .filter(ChatSession.user_id == user_id, ChatSession.status == "active")
            .order_by(ChatSession.last_message_at.desc())
        )
        total = query.count()
        items = query.offset(offset).limit(limit).all()
        return items, total

    def get_session(
        self, db: Session, session_id: int, user_id: int
    ) -> Optional[ChatSession]:
        return (
            db.query(ChatSession)
            .filter(ChatSession.id == session_id, ChatSession.user_id == user_id)
            .first()
        )

    def add_message(
        self,
        db: Session,
        session: ChatSession,
        user_id: int | None,
        role: str,
        content: str,
        is_final: bool = True,
        parent_message_id: int | None = None,
        model_name: str | None = None,
        mode_override: str | None = None,
    ) -> ChatMessage:
        # 序号
        max_seq = (
            db.query(func.max(ChatMessage.seq))
            .filter(ChatMessage.session_id == session.id)
            .scalar()
            or 0
        )
        # 将当前会话的角色模式写入消息 meta，便于前端按历史角色展示标签
        session_meta = getattr(session, "meta", None) or {}
        mode = mode_override if mode_override is not None else session_meta.get("mode")
        # 仅对 assistant 消息记录模式；user/system 保持 None，避免混淆
        msg_meta = (
            {"mode": mode}
            if (role == "assistant" and mode and mode != "default")
            else None
        )

        msg = ChatMessage(
            session_id=session.id,
            user_id=user_id,
            role=role,
            content=content,
            seq=max_seq + 1,
            is_final=is_final,
            parent_message_id=parent_message_id,
            model_name=model_name or session.model_name,
            meta=msg_meta,
        )
        db.add(msg)
        # 更新会话元数据：只在最终消息确定时才增加 message_count（保持一对 user/assistant = 2 条），占位消息不计数
        if is_final:
            new_count = int(session.message_count or 0) + 1  # type: ignore[call-arg, attr-defined]
            session.message_count = new_count  # type: ignore[assignment]
            session.last_message_at = datetime.utcnow()  # type: ignore[assignment]
        db.commit()
        return msg

    def list_messages(
        self,
        db: Session,
        session: ChatSession,
        limit: int = 50,
        before_seq: int | None = None,
    ):
        q = (
            db.query(ChatMessage)
            .filter(ChatMessage.session_id == session.id)
            .order_by(ChatMessage.seq.desc())
        )
        if before_seq is not None:
            q = q.filter(ChatMessage.seq < before_seq)
        total = q.count()
        items = q.limit(limit).all()
        # 返回按 seq 正序
        return list(reversed(items)), total

    def finalize_message(self, db: Session, message: ChatMessage, content: str):
        # 说明：流式过程中占位消息对象可能已游离 (detached)，这里使用主键重新获取以避免 InvalidRequestError
        persistent = db.query(ChatMessage).filter(ChatMessage.id == message.id).first()
        target = persistent or message
        target.content = content  # type: ignore[assignment]
        target.is_final = True  # type: ignore[assignment]
        # 更新会话统计（assistant 最终消息计数 +1）
        session = (
            db.query(ChatSession).filter(ChatSession.id == target.session_id).first()
        )
        if session is not None:
            current_count = int(getattr(session, "message_count", 0) or 0)
            session.message_count = current_count + 1  # type: ignore[assignment]
            session.last_message_at = datetime.utcnow()  # type: ignore[assignment]
        db.commit()
        # 不再 refresh，返回当前对象
        return target

    # ---------------- Additional management operations ---------------- #
    def delete_session(self, db: Session, session: ChatSession) -> None:
        """Delete a session and its messages.

        Even though FK has ondelete=CASCADE, we explicitly delete messages for SQLite safety.
        """
        db.query(ChatMessage).filter(ChatMessage.session_id == session.id).delete()
        db.delete(session)
        db.commit()

    def clear_session(self, db: Session, session: ChatSession) -> int:
        """Clear all messages inside a session but keep the session record."""
        deleted = (
            db.query(ChatMessage).filter(ChatMessage.session_id == session.id).delete()
        )
        # Reset stats / summaries
        session.message_count = 0  # type: ignore[assignment]
        session.tokens_in = 0  # type: ignore[assignment]
        session.tokens_out = 0  # type: ignore[assignment]
        session.summary_short = None  # type: ignore[assignment]
        session.summary_compressed = None  # type: ignore[assignment]
        # Option: revert last_message_at to created_at
        session.last_message_at = session.created_at  # type: ignore[assignment]
        # 标记允许下一轮自动重新命名标题
        meta = getattr(session, "meta", None) or {}
        meta["allow_auto_title"] = True
        session.meta = meta  # type: ignore[assignment]
        db.commit()
        return deleted

    def update_session_title(
        self, db: Session, session: ChatSession, new_title: str
    ) -> ChatSession:
        session.title = new_title  # type: ignore[assignment]
        db.commit()
        db.refresh(session)
        return session


chat_session_service = ChatSessionService()
